package sign

import (
	"errors"
	"fmt"
	"gitee.com/dsler-go/utils/tools"
	"github.com/dgrijalva/jwt-go"
	"net/url"
	"sort"
	"strings"
	"time"
)

type LoginClient struct {
	SignSecret  string
	TokenSecret string
	TokenExpire time.Duration
}

var (
	DefaultLoginClient = LoginClient{}
)

func InitSign(tokenSecret, signSecret string, tokenExpire time.Duration) {
	DefaultLoginClient.TokenSecret = tokenSecret
	DefaultLoginClient.SignSecret = signSecret
	DefaultLoginClient.TokenExpire = tokenExpire
}

// CreateSign 创建验签
func (c *LoginClient) CreateSign(params url.Values) string {
	var key []string
	var str = ""
	for k := range params {
		if k != "sign" {
			key = append(key, k)
		}
	}
	key = append(key, "secret")
	sort.Strings(key)
	connector := "&"
	for i := 0; i < len(key); i++ {
		if i == len(key)-1 {
			connector = ""
		}
		if key[i] == "secret" {
			str = str + "secret=" + c.SignSecret + connector
		} else {
			str = str + fmt.Sprintf("%v=%v%v", key[i], params.Get(key[i]), connector)
		}
	}
	// 自定义签名算法
	signStr := tools.Md5String(str)
	return signStr
}

// CheckSign 校验签名
func (c *LoginClient) CheckSign(signStr string, params url.Values) bool {
	getSign := c.CreateSign(params)
	if signStr == getSign {
		return true
	}
	return false
}

// CheckToken 校验token
func (c *LoginClient) CheckToken(authorization string) (int64, error) {
	if authorization == "" {
		return 0, errors.New("authorization not is empty")
	}
	// 按空格分割
	parts := strings.SplitN(authorization, " ", 2)
	if !(len(parts) == 2 && parts[0] == "Bearer") {
		return 0, errors.New("authorization format error")
	}
	// parts[1]是获取到的tokenString，我们使用之前定义好的解析JWT的函数来解析它
	myClaims, err := c.parseToken(parts[1])
	if err != nil {
		return 0, errors.New("token parse error")
	}

	return myClaims.Id, nil
}

type MyClaims struct {
	Id int64 `json:"id"`
	jwt.StandardClaims
}

// parseToken 解析JWT
func (c *LoginClient) parseToken(tokenString string) (*MyClaims, error) {
	// 解析token
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) {
		return []byte(c.TokenSecret), nil
	})
	if err != nil {
		return nil, err
	}
	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { // 校验token
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

// GetToken 获取token
func (c *LoginClient) GetToken(uid int64) (string, error) {
	// 创建一个我们自己的声明
	claims := MyClaims{
		uid, // 自定义字段
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(c.TokenExpire).Unix(), // 过期时间
			Issuer:    "dsler",                              // 签发人
		},
	}
	// 使用指定的签名方法创建签名对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 使用指定的secret签名并获得完整的编码后的字符串token
	return token.SignedString([]byte(c.TokenSecret))
}
